home *** CD-ROM | disk | FTP | other *** search
/ System Booster / System Booster.iso / Archives / GNU / GNUPLOTsrc.lha / term / latex.trm < prev    next >
Encoding:
Text File  |  1996-01-22  |  22.7 KB  |  796 lines

  1. /*
  2.  * $Id: latex.trm,v 1.50 1995/12/20 21:47:58 drd Exp $
  3.  *
  4.  */
  5.  
  6. /* GNUPLOT - latex.trm */
  7. /*
  8.  * Copyright (C) 1990 - 1993   
  9.  *
  10.  * Permission to use, copy, and distribute this software and its
  11.  * documentation for any purpose with or without fee is hereby granted, 
  12.  * provided that the above copyright notice appear in all copies and 
  13.  * that both that copyright notice and this permission notice appear 
  14.  * in supporting documentation.
  15.  *
  16.  * Permission to modify the software is granted, but not the right to
  17.  * distribute the modified code.  Modifications are to be distributed 
  18.  * as patches to released version.
  19.  *  
  20.  * This software  is provided "as is" without express or implied warranty.
  21.  * 
  22.  * This file is included by ../term.c.
  23.  *
  24.  * This terminal driver supports:
  25.  *   LaTeX pictures (latex).
  26.  *   LaTeX pictures with emTeX specials (emtex). 
  27.  *
  28.  * AUTHORS
  29.  *   David Kotz, Russell Lang
  30.  *
  31.  * send your comments or suggestions to (info-gnuplot@dartmouth.edu).
  32.  * 
  33.  */
  34.  
  35. /* modified to optimize use of \rule for long lines */
  36. /* TLDC: modified to have nice line types */
  37.  
  38. /* the following LATEX driver has been modified by 
  39.    Russell Lang, eln272v@monu1.cc.monash.oz from the
  40.    GnuTeX 1.3 driver by David Kotz, David.Kotz@Dartmouth.edu.
  41.    Since then it has been further extended by David Kotz.
  42.    EmTeX driver by Russell Lang. */
  43.  
  44. /*  9 Dec 1992  LATEX_put_text rewritten to handle \\ newlines
  45.                 Daniel S. Lewart (d-lewart@uiuc.edu) */
  46.  
  47. #ifndef GOT_DRIVER_H
  48. #include "driver.h"
  49. #endif
  50.  
  51. #ifdef TERM_REGISTER
  52. register_term(latex)
  53. #ifdef EMTEX
  54. register_term(emtex)
  55. #endif
  56. #endif
  57.  
  58. #ifdef TERM_PROTO
  59. TERM_PUBLIC void LATEX_options __P((void));
  60. TERM_PUBLIC void LATEX_init __P((void));
  61. TERM_PUBLIC void LATEX_graphics __P((void));
  62. TERM_PUBLIC void LATEX_text __P((void));
  63. TERM_PUBLIC void LATEX_put_text __P((unsigned int x, unsigned int y,
  64.                                      char str[]));
  65. TERM_PUBLIC void LATEX_linetype __P((int linetype));
  66. TERM_PUBLIC void LATEX_move __P((unsigned int x, unsigned int y));
  67. TERM_PUBLIC void LATEX_point __P((unsigned int x, unsigned int y, int number));
  68. TERM_PUBLIC void LATEX_vector __P((unsigned int ux, unsigned int uy));
  69. TERM_PUBLIC void LATEX_arrow __P((unsigned int sx, unsigned int sy, unsigned int ex, unsigned int ey, TBOOLEAN head));
  70. TERM_PUBLIC int LATEX_justify_text __P((enum JUSTIFY mode));
  71. TERM_PUBLIC int LATEX_text_angle __P((int angle));
  72. TERM_PUBLIC void LATEX_reset __P((void));
  73.  
  74. #ifdef EMTEX
  75. TERM_PUBLIC void EMTEX_init __P((void));
  76. TERM_PUBLIC void EMTEX_reset __P((void));
  77. TERM_PUBLIC void EMTEX_text __P((void));
  78. #endif
  79.  
  80. #define TINY_STEP 0.5    /* tiny steps for high quality lines */
  81.  
  82. #define LATEX_PTS_PER_INCH (72.27)
  83. #define DOTS_PER_INCH (300)    /* resolution of printer we expect to use */
  84. #define LATEX_UNIT (LATEX_PTS_PER_INCH/DOTS_PER_INCH) /* dot size in pt */
  85.  
  86. /* 5 inches wide by 3 inches high (default) */
  87. #define LATEX_XMAX (5*DOTS_PER_INCH)  /* (LATEX_PTS_PER_INCH/LATEX_UNIT*5.0) */
  88. #define LATEX_YMAX (3*DOTS_PER_INCH)  /* (LATEX_PTS_PER_INCH/LATEX_UNIT*3.0) */
  89.  
  90. #define LATEX_HTIC (5*DOTS_PER_INCH/72)        /* (5./LATEX_UNIT) */
  91. #define LATEX_VTIC (5*DOTS_PER_INCH/72)        /* (5./LATEX_UNIT) */
  92. #define LATEX_HCHAR (DOTS_PER_INCH*53/10/72)    /* (5.3/LATEX_UNIT) */
  93. #define LATEX_VCHAR (DOTS_PER_INCH*11/72)    /* (11./LATEX_UNIT) */
  94. #endif
  95.  
  96.  
  97. #ifndef TERM_PROTO_ONLY
  98. #ifdef TERM_BODY
  99.  
  100. static int LATEX_posx;
  101. static int LATEX_posy;
  102. int LATEX_fontsize = 10;
  103. char LATEX_font[MAX_ID_LEN+1] = "cmr";
  104. static enum JUSTIFY latex_justify=LEFT;
  105. static int latex_angle=0;
  106.  
  107. /* Default line-drawing character */
  108. /* the definition of plotpoint varies with linetype */
  109. #define LATEX_DOT "\\usebox{\\plotpoint}"
  110. #define LATEX_TINY_DOT "\\rule{1pt}{1pt}" /* for dots plot style */
  111.  
  112. /* POINTS */
  113. #define LATEX_POINT_TYPES 12    /* we supply more point types */
  114. static char GPFAR * GPFAR LATEX_points[] = {
  115.     "\\raisebox{-.8pt}{\\makebox(0,0){$\\Diamond$}}",
  116.     "\\makebox(0,0){$+$}",
  117.     "\\raisebox{-.8pt}{\\makebox(0,0){$\\Box$}}",
  118.     "\\makebox(0,0){$\\times$}",
  119.     "\\makebox(0,0){$\\triangle$}",
  120.     "\\makebox(0,0){$\\star$}",
  121.     "\\circle{12}", "\\circle{18}", "\\circle{24}",
  122.     "\\circle*{12}", "\\circle*{18}", "\\circle*{24}"
  123. };
  124.  
  125. /* LINES */
  126. static float LATEX_size = 0;    /* current thick of line in points */
  127. static float LATEX_dotspace = 0; /* current dotspace of line in points */
  128. #define LATEX_LINE_TYPES 6    /* number of line types below */
  129. #define LATEX_THIN_LINE 0    /* the thinnest solid line type */
  130. static struct {
  131.     float size;            /* size of dot, or thick of line in points */
  132.     float dotspace;            /* inter-dot space in points; 0 for lines */
  133.   } GPFAR LATEX_lines[] = {
  134.       {0.4, 0.0},            /* thin solid line */
  135.       {0.4, 5.0},            /* thin dotted line */
  136.       {0.8, 0.0},            /* thick solid line */
  137.       {1.0, 5.0},            /* thick dotted line */
  138.       {1.2, 0.0},            /* Thick solid line */
  139.       {1.0, 10.0},            /* thick widely dotted line */
  140.   };
  141.  
  142. /* for drawing dotted and solid lines */
  143. static void LATEX_dot_line __P((int x1, int x2, int y1, int y2));
  144. static void LATEX_solid_line __P((int x1, int x2, int y1, int y2));
  145. static void LATEX_rule __P((int code, double x, double y, double width,
  146.                             double height));
  147. static void LATEX_flushdot __P((void));
  148. #define LATEX_flushrule() LATEX_rule(2, 0.,0.,0.,0.) /* flush old rule */
  149. static TBOOLEAN LATEX_moved = TRUE;    /* pen is up after move */
  150. static float LATEX_dotsize;    /* size of LATEX_DOT in units */
  151. static TBOOLEAN LATEX_needsdot = FALSE;/* does dotted line need termination? */
  152.  
  153. #ifdef EMTEX
  154. TBOOLEAN emtex=FALSE; /* not currently using emtex */
  155. static void
  156. EMTEX_solid_line __P((int x1, int x2, int y1, int y2));
  157. #endif
  158.  
  159. /* ARROWS */
  160. /* the set of non-vertical/non-horizontal LaTeX vector slopes */
  161. /* except negatives - they are handled specially */
  162. static struct vslope {
  163.     int dx, dy;
  164. } GPFAR LATEX_slopes[] = {
  165.     {1,1}, {1,2}, {1,3}, {1,4},
  166.     {2,1}, {2,3},
  167.     {3,1}, {3,2}, {3,4},
  168.     {4,1}, {4,3},
  169.     {0,0}                    /* terminator */
  170. };
  171.  
  172. /* figure out the best arrow */
  173. static void best_latex_arrow __P((int,int,int,int,int,TBOOLEAN));
  174.  
  175. TERM_PUBLIC void LATEX_options()
  176. {
  177.     if (!END_OF_COMMAND) {
  178.         if (almost_equals(c_token,"c$ourier")) {
  179.             strcpy(LATEX_font,"cmtt");
  180.             c_token++;
  181.         }
  182.         else if (almost_equals(c_token,"r$oman")) {
  183.             strcpy(LATEX_font,"cmr");
  184.             c_token++;
  185.         }
  186.         else if (almost_equals(c_token,"d$efault")) {
  187.             strcpy(LATEX_font,"cmr");
  188.             LATEX_fontsize = 10;
  189.             c_token++;
  190.         }
  191.     }
  192.     
  193.     if (!END_OF_COMMAND) {
  194.         struct value a;
  195.         LATEX_fontsize = (int)real(const_express(&a));
  196.         term->v_char = (unsigned int)(LATEX_fontsize);
  197.         term->h_char = (unsigned int)(LATEX_fontsize);
  198.     }
  199.     sprintf(term_options,"%s %d", LATEX_font ? "courier" : "roman",
  200.         LATEX_fontsize);
  201. }
  202.  
  203.  
  204. TERM_PUBLIC void LATEX_init()
  205. {
  206. #ifdef EMTEX
  207.     emtex = FALSE;
  208. #endif
  209.     LATEX_posx = LATEX_posy = 0;
  210.     fprintf(outfile, "%% GNUPLOT: LaTeX picture\n");
  211.     fprintf(outfile, "\\setlength{\\unitlength}{%fpt}\n", LATEX_UNIT);
  212.     fprintf(outfile, 
  213.           "\\ifx\\plotpoint\\undefined\\newsavebox{\\plotpoint}\\fi\n");
  214.     LATEX_linetype(-1);
  215.     LATEX_size =0;
  216. }
  217.  
  218. TERM_PUBLIC void LATEX_graphics()
  219. {
  220.     register struct termentry *t = term;
  221.  
  222.     /* bounding box = all if multiplot, or size if not */
  223.     double xscale = multiplot ? 1 : xsize;
  224.     double yscale = multiplot ? 1 : ysize;
  225.  
  226.     fprintf(outfile, "\\begin{picture}(%d,%d)(0,0)\n", (int)(xscale*t->xmax), (int)(yscale*t->ymax));
  227.     fprintf(outfile, "\\font\\gnuplot=%s10 at %dpt\n", LATEX_font, LATEX_fontsize);
  228.     fprintf(outfile, "\\gnuplot\n");
  229. }
  230.  
  231.  
  232. TERM_PUBLIC void LATEX_text()
  233. {
  234.     LATEX_flushrule();
  235.     LATEX_flushdot();
  236.     fprintf(outfile, "\\end{picture}\n");
  237.     LATEX_posx = LATEX_posy = 0; /* current position */
  238.     LATEX_moved = TRUE;    /* pen is up after move */
  239. }
  240.  
  241. TERM_PUBLIC void LATEX_linetype(linetype)
  242.     int linetype;
  243. {
  244.     float size;
  245.  
  246.     if (linetype >= LATEX_LINE_TYPES)
  247.      linetype %= LATEX_LINE_TYPES;
  248.  
  249. #ifdef EMTEX
  250.     if (!emtex)
  251. #endif
  252.     LATEX_flushrule();
  253.     LATEX_flushdot();
  254.  
  255.     /* Find the new desired line thickness. */
  256.     /* negative linetypes (for axes) use a thin line */
  257.     /* only relevant for drawing axes/border in 3d */
  258.     size = (linetype >= 0 ? LATEX_lines[linetype].size 
  259.           : LATEX_lines[LATEX_THIN_LINE].size);
  260.  
  261.     /* If different from current size, redefine \plotpoint */
  262.     if (size != LATEX_size) {
  263.        fprintf(outfile, 
  264.              "\\sbox{\\plotpoint}{\\rule[%.3fpt]{%.3fpt}{%.3fpt}}%%\n",
  265.              -size/2, size, size);
  266. #ifdef EMTEX
  267.         if (emtex)         /* change line width */
  268.         fprintf(outfile, "\\special{em:linewidth %.1fpt}%%\n", size);
  269. #endif
  270.     }
  271.     
  272.     LATEX_size = size;
  273.     LATEX_dotsize = size / LATEX_UNIT;
  274.     LATEX_dotspace = (linetype >= 0) ? LATEX_lines[linetype].dotspace : 0;
  275.     LATEX_moved = TRUE;            /* reset */
  276. }
  277.  
  278. TERM_PUBLIC void LATEX_move(x,y)
  279.     unsigned int x,y;
  280. {
  281.     LATEX_flushdot();
  282.  
  283.     LATEX_posx = x;
  284.     LATEX_posy = y;
  285.     LATEX_moved = TRUE;            /* reset */
  286. }
  287.  
  288.  
  289. TERM_PUBLIC void LATEX_point(x,y, number)        /* version of line_and_point */
  290.     unsigned int x,y;
  291.     int number;                /* type of point */
  292. {
  293.     LATEX_move(x,y);
  294.     
  295.     /* Print the character defined by 'number'; number < 0 means 
  296.       to use a dot, otherwise one of the defined points. */
  297.     fprintf(outfile, "\\put(%d,%d){%s}\n", x, y, 
  298.           (number < 0 ? LATEX_TINY_DOT
  299.            : LATEX_points[number % LATEX_POINT_TYPES]));
  300. }
  301.  
  302.  
  303. TERM_PUBLIC void LATEX_vector(ux,uy)
  304.     unsigned int ux,uy;
  305. {
  306.     if (LATEX_dotspace == 0.0) {
  307.        /* solid line */
  308. #ifdef EMTEX
  309.        if (emtex)
  310.         EMTEX_solid_line(LATEX_posx, (int)ux, LATEX_posy, (int)uy);
  311.        else
  312. #endif
  313.         LATEX_solid_line(LATEX_posx, (int)ux, LATEX_posy, (int)uy);
  314.     } else
  315.      /* dotted line */
  316.      LATEX_dot_line(LATEX_posx, (int)ux, LATEX_posy, (int)uy);
  317.  
  318.     LATEX_posx = ux;
  319.     LATEX_posy = uy;
  320. }
  321.  
  322. static void
  323. LATEX_solid_line(x1,x2, y1,y2)
  324.     int x1,x2, y1,y2;
  325. {
  326.     float slope;
  327.     int inc;
  328.     float dx,dy,x,y;
  329.     float offset,length;
  330.     int code;                /* possibly combine with previous rule */
  331.  
  332.     /* we draw a solid line using the current line thickness (size) */
  333.     /* we do it with lots of \\rules */
  334.  
  335.     if (x1 == x2 && y1 == y2) { /* zero-length line - just a dot */
  336.        if (LATEX_moved) {
  337.           LATEX_flushrule();
  338.           /* plot a dot */
  339.           fprintf(outfile, "\\put(%u,%u){%s}\n", x1, y1, LATEX_DOT);
  340.        }
  341.     } else {
  342.        code = (LATEX_moved ? 0 : 1); /* no combine after move */
  343.            LATEX_moved = FALSE;
  344.        if (x1 == x2)        /* vertical line - special case */
  345.         LATEX_rule(code, (double)x1, (double)y1,
  346.                LATEX_dotsize, (double)y2-y1);
  347.        else if (y1 == y2)    /* horizontal line - special case */
  348.         LATEX_rule(code, (double)x1, (double)y1, (double)x2-x1,
  349.                LATEX_dotsize);
  350.        else {
  351.           dx = (float)x2-x1;
  352.           dy = (float)y2-y1;
  353.           slope = dy/dx;
  354.           if (abs(slope) <= 1.0) {
  355.             /* longer than high */
  356.             x = min(abs(dx),(0.25+1.0/abs(slope))*LATEX_dotsize);
  357.             offset = sign(dy)*min(LATEX_dotsize,abs(dy));
  358.             dy = dy - offset;
  359.             length = x*LATEX_UNIT;
  360.             inc = (x == abs(dx) ? 1 : max(1,abs(dy)/TINY_STEP+0.5));
  361.             if (inc == 1) {
  362.               fprintf(outfile,"\\put(%u,%.2f){\\rule{%.3fpt}{%.3fpt}}\n",
  363.              (x2>=x1? x1 : x2), ((float)y1+y2-LATEX_dotsize)/2,
  364.              length, LATEX_dotsize*LATEX_UNIT);
  365.             } else {
  366.               dy = dy/inc;
  367.               dx = (dx-sign(dx)*x)/(inc-1);
  368. fprintf(outfile,"\\multiput(%.2f,%.2f)(%.3f,%.3f){%u}{\\rule{%.3fpt}{%.3fpt}}\n",
  369.                (dx>=0.0? (float)x1 : x1-x), 
  370.                (float)y1-(abs(dy)-offset)/2, 
  371.                dx, dy, inc, length, abs(dy)*LATEX_UNIT);
  372.             }
  373. /* done with one section, now smooth it */
  374.             x = x/2;
  375.             dx = sign(dx) * x;
  376.             dx = (float)x2 - x1 - dx;
  377.             dy = (float)y2 - y1;
  378. fprintf(outfile,"\\multiput(%.2f,%.2f)(%.3f,%.3f){2}{\\rule{%.3fpt}{%.3fpt}}\n",
  379.              (dx>=0.0? (float)x1 : x1-x), (float)y1-LATEX_dotsize/2,
  380.              dx, dy, x*LATEX_UNIT, LATEX_dotsize*LATEX_UNIT);
  381.                 LATEX_moved = TRUE;
  382.           } else {
  383.             /* higher than long */
  384.             y = min(abs(dy),(0.25+abs(slope))*LATEX_dotsize);
  385.             offset = sign(dx)*min(LATEX_dotsize,abs(dx));
  386.             dx = dx - offset;
  387.             length = y*LATEX_UNIT;
  388.             inc = (y == abs(dy) ? 1 : max(1,abs(dx)/TINY_STEP+0.5));
  389.             if (inc == 1) {
  390.              fprintf(outfile,"\\put(%.2f,%u){\\rule{%.3fpt}{%.3fpt}}\n",
  391.              ((float)x1+x2-LATEX_dotsize)/2, (y2>=y1? y1 : y2),
  392.              LATEX_dotsize*LATEX_UNIT, length);
  393.             } else {
  394.               dx = dx/inc;
  395.               dy = (dy-sign(dy)*y)/(inc-1);
  396. fprintf(outfile,"\\multiput(%.2f,%.2f)(%.3f,%.3f){%u}{\\rule{%.3fpt}{%.3fpt}}\n",
  397.                (float)x1-(abs(dx)-offset)/2, 
  398.                (dy>=0? (float)y1 : y1-y), 
  399.                dx, dy, inc, abs(dx)*LATEX_UNIT, length);
  400.             }
  401. /* done with one section, now smooth it */
  402.             y = y/2;
  403.             dx = (float)x2 - x1;
  404.             dy = sign(dy) * y;
  405.             dy = (float)y2 - y1 - dy;
  406. fprintf(outfile,"\\multiput(%.2f,%.2f)(%.3f,%.3f){2}{\\rule{%.3fpt}{%.3fpt}}\n",
  407.              (float)x1-LATEX_dotsize/2, (dy>=0.0? (float)y1 : y1-y),
  408.              dx, dy, LATEX_dotsize*LATEX_UNIT, y*LATEX_UNIT);
  409.                 LATEX_moved = TRUE;
  410.           }
  411.        }
  412.     }
  413. }
  414.  
  415. /* Draw a \rule. Width or height may be negative; we can correct.
  416.  * The rule is never output immediately. The previous rule is output
  417.  * as-is if code is 0, and the previous rule is
  418.  * combined with the current rule (if possible) if code is 1.
  419.  * The previous rule is output, and the new one ignored, if code is 2.
  420.  */
  421. static void
  422. LATEX_rule(code, x,y, width, height)
  423.     int code;                /* how do we treat this rule? */
  424.     double x, y;
  425.     double width;
  426.     double height;
  427. {  
  428.     static float lastx, lasty;
  429.     static float lastw, lasth;
  430.     static TBOOLEAN valid = FALSE; /* is 'last' data valid? */
  431.     TBOOLEAN combine = (code == 1);
  432.     TBOOLEAN flush = (code == 2);
  433.  
  434.     if (!flush)
  435.      if (width == 0 || height == 0)
  436.        return;            /* ignore this rule */
  437.  
  438.     if (valid && combine) {
  439.        /* try to combine new rule with old rule */
  440.        if ((int)lastx == (int)x && lastw == width) { /* vertical rule */
  441.           if (lasth * height >= 0) { /* same sign */
  442.              lasth += height;
  443.              return;
  444.           }
  445.        } else if ((int)lasty == (int)y && lasth == height){ /* horiz rule */
  446.           if (lastw * width >= 0) { /* same sign */
  447.              lastw += width;
  448.              return;
  449.           }
  450.        }
  451.        /* oh well, output last and remember the new one */
  452.     }
  453.  
  454.     if (valid) {
  455.        /* output the rule */
  456.        if (lastw < 0) {
  457.           lastx += lastw;
  458.           lastw = -lastw;
  459.        }
  460.        if (lasth < 0) {
  461.           lasty += lasth;
  462.           lasth = -lasth;
  463.        }
  464.  
  465.        /* if very small use canned dot */
  466.        if (lastw < LATEX_dotsize || lasth < LATEX_dotsize)
  467.         fprintf(outfile, "\\put(%.1f,%.1f){%s}\n",       
  468.                lastx, lasty, LATEX_DOT);
  469.        else
  470.         fprintf(outfile, "\\put(%.1f,%.1f){\\rule[%.3fpt]{%.3fpt}{%.3fpt}}\n",
  471.                lastx, lasty, -LATEX_dotsize*LATEX_UNIT/2,
  472.                lastw*LATEX_UNIT, lasth*LATEX_UNIT);
  473.     }
  474.     
  475.     if (flush) {
  476.        valid = FALSE;
  477.     } else {
  478.        lastx = x; lasty = y;
  479.        lastw = width; lasth = height;
  480.        valid = TRUE;
  481.     }
  482. }
  483.  
  484. static void
  485. LATEX_dot_line(x1,x2, y1,y2)
  486.     int x1,x2, y1,y2;
  487. {
  488.     static float LATEX_left;    /* fraction of space left after last dot */
  489.  
  490.     /* we draw a dotted line using the current dot spacing */
  491.  
  492.     if (LATEX_moved)
  493.      LATEX_left = 1.0;        /* reset after a move */
  494.  
  495.     /* zero-length line? */
  496.     if (x1 == x2 && y1 == y2) {
  497.        if (LATEX_moved)
  498.         /* plot a dot */
  499.         fprintf(outfile, "\\put(%u,%u){%s}\n", x1, y1, LATEX_DOT);
  500.     } else {
  501.        float dotspace = LATEX_dotspace / LATEX_UNIT;
  502.        float x,y;            /* current position */
  503.        float xinc, yinc;    /* increments */
  504.        float slope;        /* slope of line */
  505.        float lastx = -1;    /* last x point plotted */
  506.        float lasty = -1;    /* last y point plotted */
  507.        int numdots = 0;    /* number of dots in this section */
  508.  
  509.        /* first, figure out increments for x and y */
  510.        if (x2 == x1) {
  511.           xinc = 0.0;
  512.           yinc = (y2-y1>0)?dotspace:-dotspace;
  513.        } else {
  514.           slope = ((float)y2-y1)/((float)x2-x1);
  515.           xinc = dotspace / sqrt(1 + slope*slope) * sign(x2-x1);
  516.           yinc = slope * xinc;
  517.        }
  518.        
  519.        /* now draw the dotted line */
  520.        /* we take into account where we last placed a dot */
  521.        for (x=x1 + xinc*(1-LATEX_left), y=y1 + yinc*(1-LATEX_left);
  522.            (x2-x)*xinc >= 0 && (y2-y)*yinc >= 0; /* same sign or zero */
  523.            lastx = x, x += xinc, 
  524.            lasty = y, y += yinc)
  525.         numdots++;
  526.        if (numdots == 1)
  527.         fprintf(outfile, "\\put(%.2f,%.2f){%s}\n",
  528.            lastx, lasty, LATEX_DOT);
  529.        else if (numdots > 0)
  530.         fprintf(outfile, "\\multiput(%u,%u)(%.3f,%.3f){%u}{%s}\n",
  531.                x1, y1, xinc, yinc, numdots, LATEX_DOT);
  532.  
  533.        /* how much is left over, as a fraction of dotspace? */
  534.        if (xinc != 0.0)            /* xinc must be nonzero */
  535.         if (lastx >= 0)
  536.           LATEX_left = abs(x2 - lastx) / abs(xinc);
  537.         else
  538.           LATEX_left += abs(x2-x1) / abs(xinc);
  539.        else
  540.         if (lasty >= 0)
  541.           LATEX_left = abs(y2 - lasty) / abs(yinc);
  542.         else
  543.           LATEX_left += abs(y2-y1) / abs(yinc);
  544.     }
  545.  
  546.     LATEX_needsdot = (LATEX_left > 0);
  547.  
  548.     LATEX_moved = FALSE;
  549. }
  550.  
  551. static void
  552. LATEX_flushdot()
  553. {
  554.     if (LATEX_needsdot) 
  555.      fprintf(outfile, "\\put(%d,%d){%s}\n", 
  556.             LATEX_posx, LATEX_posy, LATEX_DOT);
  557.     LATEX_needsdot = FALSE;
  558. }
  559.  
  560. TERM_PUBLIC void LATEX_arrow(sx,sy, ex,ey, head)
  561.     unsigned int sx,sy, ex,ey;
  562.     TBOOLEAN head;
  563. {
  564.     best_latex_arrow(sx,sy, ex,ey, 1, head);
  565.  
  566.     LATEX_posx = ex;
  567.     LATEX_posy = ey;
  568. }
  569.  
  570. static void best_latex_arrow(sx,sy, ex,ey, who, head)
  571.     int sx,sy, ex,ey;        /* start and end points */
  572.     int who;                /* 1=LATEX, 2=EEPIC */
  573.     TBOOLEAN head;
  574. {
  575.     int dx = ex - sx;
  576.     int dy = ey - sy;
  577.     float m;                /* slope of line */
  578.     float arrowslope;        /* slope of arrow */
  579.     float minerror = 0;        /* best-case error */
  580.     struct vslope *slope;    /* one of the slopes */
  581.     struct vslope *bestslope;    /* the slope with min error */
  582.  
  583.     /* We try to draw a real arrow (ie, \vector). If we can't get
  584.     * a slope that is close, we draw a bent arrow.
  585.     */
  586.  
  587.     if (dx == 0) {
  588.        /* vertical arrow */
  589.        fprintf(outfile, "\\put(%d,%d){\\%s(0,%d){%d}}\n",
  590.              sx, sy, head ? "vector":"line", 
  591.              sign(ey-sy), abs(ey-sy));
  592.     } else if (dy == 0) {
  593.        /* horizontal arrow */
  594.        fprintf(outfile, "\\put(%d,%d){\\%s(%d,0){%d}}\n",
  595.              sx, sy, head ? "vector":"line",
  596.              sign(ex-sx), abs(ex-sx));
  597.     } else {
  598.        /* Slanted arrow. We'll give it a try.
  599.         * we try to find the closest-slope arrowhead.
  600.         */
  601.        bestslope = NULL;
  602.        minerror = 0; /* to shut up turbo C */
  603.        m = abs((float)dy/dx); /* the slope we want */
  604.        for (slope = LATEX_slopes; slope->dx != 0.0; slope++) {
  605.           /* find the slope of the arrow */
  606.           arrowslope = (float) slope->dy / slope->dx;
  607.           if (bestslope == NULL || abs(m-arrowslope) < minerror) {
  608.              minerror = abs(m-arrowslope);
  609.              bestslope = slope;
  610.           }
  611.        }
  612.  
  613.        /* now we have the best slope arrow */
  614.        /* maybe it's exactly the right slope! */
  615.        if (minerror == 0.0)    /* unlikely but possible */
  616.         fprintf(outfile, "\\put(%d,%d){\\%s(%d,%d){%d}}\n",
  617.                sx, sy, head ? "vector" : "line",
  618.                bestslope->dx*sign(ex-sx), bestslope->dy*sign(ey-sy),
  619.                abs(ex-sx));
  620.        else {
  621.           /* we draw the line the usual way, with thin lines */
  622. #ifdef EMTEX
  623.           if (emtex) {
  624.              LATEX_linetype(LATEX_THIN_LINE);
  625.              EMTEX_solid_line(sx,ex,sy,ey);
  626.           } else 
  627. #endif
  628.             if (who == 1) {
  629.                LATEX_linetype(LATEX_THIN_LINE);
  630.                LATEX_solid_line(sx,ex,sy,ey);
  631.             }
  632. #ifdef EEPIC
  633.             else {
  634.                EEPIC_move(sx,sy);
  635.                EEPIC_vector(ex,ey);
  636.             }
  637. #endif /* EEPIC */
  638.           /* and then draw an arrowhead (a short vector) there */
  639.             if (head)
  640.                   fprintf(outfile, "\\put(%d,%d){\\vector(%d,%d){0}}\n",
  641.                 ex, ey, 
  642.                 bestslope->dx*sign(ex-sx), bestslope->dy*sign(ey-sy));
  643.        }
  644.     }
  645. }
  646.  
  647. TERM_PUBLIC void LATEX_put_text(x, y, str)
  648.     unsigned int x,y;   /* reference point of string */
  649.     char str[];         /* the text */
  650. {
  651.     static char *justify[] = { "[l]", "", "[r]" };
  652.     int flag,i;
  653.  
  654.     /* ignore empty strings */
  655.     if (str[0] == '\0')
  656.         return;
  657.  
  658.     for (flag=FALSE,i=0; str[i] && !flag;)
  659.         flag = (str[i++] == '\\') && (str[i++] == '\\');
  660.  
  661.     fprintf(outfile, "\\put(%d,%d)", x, y);
  662.     if (flag)
  663.         fprintf(outfile, "{\\makebox(0,0)%s{\\shortstack{%s}}}\n",
  664.             justify[latex_justify], str);
  665.     else
  666.         fprintf(outfile, "{\\makebox(0,0)%s{%s}}\n",
  667.             justify[latex_justify], str);
  668. }
  669.  
  670. TERM_PUBLIC int LATEX_justify_text(mode)
  671.     enum JUSTIFY mode;
  672. {
  673.     latex_justify = mode;
  674.     return (TRUE);
  675. }
  676.  
  677. TERM_PUBLIC int LATEX_text_angle(angle)
  678.     int angle;
  679. {
  680.     /* we can't really write text vertically, but this will 
  681.       put the ylabel centred at the left of the plot, and
  682.       then we'll make a \shortstack */
  683.     latex_angle = angle;
  684.     return (TRUE);
  685. }
  686.  
  687. TERM_PUBLIC void LATEX_reset()
  688. {
  689.     LATEX_posx = LATEX_posy = 0; /* current position */
  690.     LATEX_moved = TRUE;    /* pen is up after move */
  691. }
  692.  
  693.  
  694. #ifdef EMTEX
  695.  
  696. TERM_PUBLIC void EMTEX_init()
  697. {
  698.     emtex=TRUE;
  699.     LATEX_posx = LATEX_posy = 0;
  700.     fprintf(outfile, "%% GNUPLOT: LaTeX picture with emtex specials\n");
  701.     fprintf(outfile, "\\setlength{\\unitlength}{%fpt}\n", LATEX_UNIT);
  702.     fprintf(outfile, 
  703.           "\\ifx\\plotpoint\\undefined\\newsavebox{\\plotpoint}\\fi\n");
  704.     LATEX_linetype(-1);
  705. }
  706.  
  707.  
  708. TERM_PUBLIC void EMTEX_reset()
  709. {
  710.     emtex=FALSE;
  711.     LATEX_posx = LATEX_posy = 0;
  712. }
  713.  
  714.  
  715. TERM_PUBLIC void EMTEX_text()
  716. {
  717.     fprintf(outfile, "\\end{picture}\n");
  718. }
  719.  
  720.  
  721. static void
  722. EMTEX_solid_line(x1,x2, y1,y2)
  723.     int x1,x2, y1,y2;
  724. {
  725.     /* emtex special solid line */
  726.     if (LATEX_moved)
  727.         fprintf(outfile, "\\put(%d,%d){\\special{em:moveto}}\n", x1, y1);
  728.     if ( (x1!=x2) || (y1!=y2) )
  729.         fprintf(outfile, "\\put(%d,%d){\\special{em:lineto}}\n", x2, y2);
  730.     LATEX_posx = x2;
  731.     LATEX_posy = y2;
  732.     LATEX_moved = FALSE;
  733. }
  734.  
  735.  
  736. #endif /* EMTEX */
  737.  
  738. #endif /* TERM_BODY */
  739. #endif /* TERM_PROTO_ONLY */
  740.  
  741. #ifdef TERM_TABLE
  742.  
  743. TERM_TABLE_START(latex_driver)
  744.      "latex", "LaTeX picture environment",
  745.        LATEX_XMAX, LATEX_YMAX, LATEX_VCHAR, LATEX_HCHAR, 
  746.        LATEX_VTIC, LATEX_HTIC, LATEX_options, LATEX_init, LATEX_reset, 
  747.        LATEX_text, null_scale, LATEX_graphics, LATEX_move, LATEX_vector, 
  748.        LATEX_linetype, LATEX_put_text, LATEX_text_angle, 
  749.        LATEX_justify_text, LATEX_point, LATEX_arrow, set_font_null
  750. TERM_TABLE_END(latex_driver)
  751. #undef LAST_TERM
  752. #define LAST_TERM latex_driver
  753.  
  754.  
  755. #ifdef EMTEX
  756. TERM_TABLE_START(emtex_driver)
  757.       "emtex", "LaTeX picture environment with emTeX specials",
  758.        LATEX_XMAX, LATEX_YMAX, LATEX_VCHAR, LATEX_HCHAR, 
  759.        LATEX_VTIC, LATEX_HTIC, LATEX_options, EMTEX_init, EMTEX_reset, 
  760.        EMTEX_text, null_scale, LATEX_graphics, LATEX_move, LATEX_vector, 
  761.        LATEX_linetype, LATEX_put_text, LATEX_text_angle, 
  762.        LATEX_justify_text, LATEX_point, LATEX_arrow, set_font_null
  763. TERM_TABLE_END(emtex_driver)
  764.  
  765. #undef LAST_TERM
  766. #define LAST_TERM emtex_driver
  767.  
  768. #endif /* EMTEX */
  769. #endif /* TERM_TABLE */
  770.  
  771.  
  772. #ifdef TERM_HELP
  773. START_HELP(latex)
  774. "1 latex",
  775. "?set terminal latex",
  776. "?latex",
  777. " The LaTeX and emTeX driver allows one to specify a font type and a font size",
  778. " for the labels around a `gnuplot` graph.",
  779. "",
  780. " Options are:",
  781. "",
  782. " Fonts:",
  783. "       default          (Roman 10 point),",
  784. "       courier",
  785. "       roman",
  786. "",
  787. " at any size you specify.  (BEWARE: METAFONT will not like odd sizes.) e.g.",
  788. "",
  789. "       gnuplot> set term latex courier 5",
  790. "",
  791. " Unless your driver is capable of building fonts at any size (e.g. dvips),",
  792. " stick to the standard 10, 11 and 12 point size."
  793. END_HELP(latex)
  794. #endif
  795.  
  796.